package com.clj.fastble.bluetooth;

import com.clj.fastble.BleManager;
import com.clj.fastble.callback.BleGattCallback;
import com.clj.fastble.callback.BleIndicateCallback;
import com.clj.fastble.callback.BleMtuChangedCallback;
import com.clj.fastble.callback.BleNotifyCallback;
import com.clj.fastble.callback.BleReadCallback;
import com.clj.fastble.callback.BleRssiCallback;
import com.clj.fastble.callback.BleWriteCallback;
import com.clj.fastble.data.BleConnectStateParameter;
import com.clj.fastble.data.BleDevice;
import com.clj.fastble.data.BleMsg;
import com.clj.fastble.exception.ConnectException;
import com.clj.fastble.exception.OtherException;
import com.clj.fastble.exception.TimeoutException;
import com.clj.fastble.utils.BleLog;

import ohos.bluetooth.ProfileBase;
import ohos.bluetooth.ble.BlePeripheralCallback;
import ohos.bluetooth.ble.BlePeripheralDevice;
import ohos.bluetooth.ble.GattCharacteristic;
import ohos.bluetooth.ble.GattDescriptor;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;
import ohos.utils.PacMap;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * BleBluetooth
 */
public class BleBluetooth {

    // 链接
    private BleGattCallback bleGattCallback;

    // 信号强度
    private BleRssiCallback bleRssiCallback;

    // 传输单元大小
    private BleMtuChangedCallback bleMtuChangedCallback;

    // 接收通知的手段快，丢数据
    private HashMap<String, BleNotifyCallback> bleNotifyCallbackHashMap = new HashMap<>();

    // 接收通知的手段不丢数据
    private HashMap<String, BleIndicateCallback> bleIndicateCallbackHashMap = new HashMap<>();
    private HashMap<String, BleWriteCallback> bleWriteCallbackHashMap = new HashMap<>();
    private HashMap<String, BleReadCallback> bleReadCallbackHashMap = new HashMap<>();

    private LastState lastState;
    private boolean isActiveDisconnect = false;
    private BleDevice bleDevice;
    private BlePeripheralDevice bluetoothGatt;
    private MainHandler mainHandler = new MainHandler(EventRunner.getMainEventRunner());
    private int connectRetryCount = 0;

    public BleBluetooth(BleDevice bleDevice) {
        this.bleDevice = bleDevice;
    }

    /**
     * newBleConnector
     * @return BleConnector
     */
    public BleConnector newBleConnector() {
        return new BleConnector(this);
    }

    /**
     * addConnectGattCallback
     * @param callback callback
     */
    public synchronized void addConnectGattCallback(BleGattCallback callback) {
        bleGattCallback = callback;
    }

    /**
     * removeConnectGattCallback
     */
    public synchronized void removeConnectGattCallback() {
        bleGattCallback = null;
    }

    /**
     * addNotifyCallback
     * @param uuid uuid
     * @param bleNotifyCallback bleNotifyCallback
     */
    public synchronized void addNotifyCallback(String uuid, BleNotifyCallback bleNotifyCallback) {
        bleNotifyCallbackHashMap.put(uuid, bleNotifyCallback);
    }

    /**
     * addIndicateCallback
     * @param uuid uuid
     * @param bleIndicateCallback bleIndicateCallback
     */
    public synchronized void addIndicateCallback(String uuid, BleIndicateCallback bleIndicateCallback) {
        bleIndicateCallbackHashMap.put(uuid, bleIndicateCallback);
    }

    /**
     * addWriteCallback
     * @param uuid uuid
     * @param bleWriteCallback bleWriteCallback
     */
    public synchronized void addWriteCallback(String uuid, BleWriteCallback bleWriteCallback) {
        bleWriteCallbackHashMap.put(uuid, bleWriteCallback);
    }

    /**
     * addReadCallback
     * @param uuid uuid
     * @param bleReadCallback bleReadCallback
     */
    public synchronized void addReadCallback(String uuid, BleReadCallback bleReadCallback) {
        bleReadCallbackHashMap.put(uuid, bleReadCallback);
    }

    /**
     * removeNotifyCallback
     * @param uuid uuid
     */
    public synchronized void removeNotifyCallback(String uuid) {
        if (bleNotifyCallbackHashMap.containsKey(uuid)) {
            bleNotifyCallbackHashMap.remove(uuid);
        }
    }

    /**
     * removeIndicateCallback
     * @param uuid uuid
     */
    public synchronized void removeIndicateCallback(String uuid) {
        if (bleIndicateCallbackHashMap.containsKey(uuid)) {
            bleIndicateCallbackHashMap.remove(uuid);
        }
    }

    /**
     * removeWriteCallback
     * @param uuid uuid
     */
    public synchronized void removeWriteCallback(String uuid) {
        if (bleWriteCallbackHashMap.containsKey(uuid)) {
            bleWriteCallbackHashMap.remove(uuid);
        }
    }

    /**
     * removeReadCallback
     * @param uuid uuid
     */
    public synchronized void removeReadCallback(String uuid) {
        if (bleReadCallbackHashMap.containsKey(uuid)) {
            bleReadCallbackHashMap.remove(uuid);
        }
    }

    /**
     * clearCharacterCallback
     */
    public synchronized void clearCharacterCallback() {
        if (bleNotifyCallbackHashMap != null) {
            bleNotifyCallbackHashMap.clear();
        }
        if (bleIndicateCallbackHashMap != null) {
            bleIndicateCallbackHashMap.clear();
        }
        if (bleWriteCallbackHashMap != null) {
            bleWriteCallbackHashMap.clear();
        }
        if (bleReadCallbackHashMap != null) {
            bleReadCallbackHashMap.clear();
        }
    }

    /**
     * addRssiCallback
     * @param callback callback
     */
    public synchronized void addRssiCallback(BleRssiCallback callback) {
        bleRssiCallback = callback;
    }

    /**
     * removeRssiCallback
     */
    public synchronized void removeRssiCallback() {
        bleRssiCallback = null;
    }

    /**
     * addMtuChangedCallback
     * @param callback callback
     */
    public synchronized void addMtuChangedCallback(BleMtuChangedCallback callback) {
        bleMtuChangedCallback = callback;
    }

    /**
     * removeMtuChangedCallback
     */
    public synchronized void removeMtuChangedCallback() {
        bleMtuChangedCallback = null;
    }

    /***
     * getDeviceKey
     * @return String
     */
    public String getDeviceKey() {
        return bleDevice.getKey();
    }

    /**
     * getDevice
     * @return BleDevice
     */
    public BleDevice getDevice() {
        return bleDevice;
    }

    /**
     * BlePeripheralDevice
     * @return BlePeripheralDevice
     */
    public BlePeripheralDevice getBluetoothGatt() {
        return bluetoothGatt;
    }

    /**
     * ble connect
     * @param bleDevice bleDevice
     * @param autoConnect autoConnect
     * @param callback callback
     * @return BlePeripheralDevice
     */
    public synchronized BlePeripheralDevice connect(
            BleDevice bleDevice, boolean autoConnect, BleGattCallback callback) {
        return connect(bleDevice, autoConnect, callback, 0);
    }

    /**
     * ble connect
     * @param bleDevice bleDevice
     * @param autoConnect autoConnect
     * @param callback callback
     * @param connectRetryCount connectRetryCount
     * @return BlePeripheralDevice
     */
    public synchronized BlePeripheralDevice connect(
            BleDevice bleDevice, boolean autoConnect, BleGattCallback callback, int connectRetryCount) {
        BleLog.info(
                "connect device: ",
                bleDevice.getName()
                        + "mac: "
                        + bleDevice.getMac()
                        + "autoConnect: "
                        + autoConnect
                        + "currentThread: "
                        + Thread.currentThread().getId()
                        + "connectCount:"
                        + (connectRetryCount + 1));
        if (connectRetryCount == 0) {
            this.connectRetryCount = 0;
        }

        addConnectGattCallback(callback);

        lastState = LastState.CONNECT_CONNECTING;

        bluetoothGatt = bleDevice.getBleDevice();
        bleDevice.getBleDevice().connect(autoConnect, coreGattCallback);

        if (bluetoothGatt != null) {
            if (bleGattCallback != null) {
                bleGattCallback.onStartConnect();
            }

            InnerEvent innerEvent = InnerEvent.get(BleMsg.MSG_CONNECT_OVER_TIME);
            mainHandler.sendEvent(innerEvent, BleManager.getInstance().getConnectOverTime());

        } else {
            disconnectGatt();
            refreshDeviceCache();
            closeBluetoothGatt();
            lastState = LastState.CONNECT_FAILURE;
            BleManager.getInstance().getMultipleBluetoothController().removeConnectingBle(BleBluetooth.this);
            if (bleGattCallback != null){
                bleGattCallback.onConnectFail(bleDevice, new OtherException("GATT connect exception occurred!"));
            }
        }
        return bluetoothGatt;
    }

    /**
     * disconnect
     */
    public synchronized void disconnect() {
        isActiveDisconnect = true;
        disconnectGatt();
    }

    /**
     * destroy
     */
    public synchronized void destroy() {
        lastState = LastState.CONNECT_IDLE;
        disconnectGatt();
        refreshDeviceCache();
        closeBluetoothGatt();
        removeConnectGattCallback();
        removeRssiCallback();
        removeMtuChangedCallback();
        clearCharacterCallback();
        mainHandler.removeAllEvent();
    }

    private synchronized void disconnectGatt() {
        if (bluetoothGatt != null) {
            bluetoothGatt.disconnect();
        }
    }

    private synchronized void refreshDeviceCache() {
        try {
            final Method refresh = BlePeripheralDevice.class.getMethod("refresh");
            if (refresh != null && bluetoothGatt != null) {
                boolean success = (Boolean) refresh.invoke(bluetoothGatt);
                BleLog.info("refreshDeviceCache", " is success:  " + success);
            }
        } catch (Exception e) {
            BleLog.info("exception occur while refreshing device: ", e.getMessage());
        }
    }

    private synchronized void closeBluetoothGatt() {
        if (bluetoothGatt != null) {
            bluetoothGatt.close();
        }
    }

    private final class MainHandler extends EventHandler {
        MainHandler(EventRunner looper) {
            super(looper);
        }

        @Override
        protected void processEvent(InnerEvent msg) {
            super.processEvent(msg);

            switch (msg.eventId) {
                case BleMsg.MSG_CONNECT_FAIL: {
                    disconnectGatt();
                    refreshDeviceCache();
                    closeBluetoothGatt();

                    if (connectRetryCount < BleManager.getInstance().getReConnectCount()) {
                        BleLog.error(
                                "Connect fail, try reconnect "
                                        + BleManager.getInstance().getReConnectInterval()
                                        + " millisecond later");
                        ++connectRetryCount;

                        InnerEvent message =
                                InnerEvent.get(BleMsg.MSG_RECONNECT, BleManager.getInstance().getReConnectInterval());
                        mainHandler.sendEvent(message);
                    } else {
                        lastState = LastState.CONNECT_FAILURE;
                        BleManager.getInstance()
                                .getMultipleBluetoothController()
                                .removeConnectingBle(BleBluetooth.this);

                        BleConnectStateParameter para = (BleConnectStateParameter) msg.object;
                        int status = para.getStatus();
                        if (bleGattCallback != null) {
                            bleGattCallback.onConnectFail(bleDevice, new ConnectException(bluetoothGatt, status));
                        }
                    }
                }
                break;

                case BleMsg.MSG_DISCONNECTED: {
                    lastState = LastState.CONNECT_DISCONNECT;
                    BleManager.getInstance().getMultipleBluetoothController().removeBleBluetooth(BleBluetooth.this);

                    disconnect();
                    refreshDeviceCache();
                    closeBluetoothGatt();
                    removeRssiCallback();
                    removeMtuChangedCallback();
                    clearCharacterCallback();
                    mainHandler.removeAllEvent();

                    BleConnectStateParameter para = (BleConnectStateParameter) msg.object;
                    boolean isActive = para.isActive();
                    int status = para.getStatus();
                    if (bleGattCallback != null) {
                        bleGattCallback.onDisConnected(isActive, bleDevice, bluetoothGatt, status);
                    }
                }
                break;

                case BleMsg.MSG_RECONNECT: {
                    connect(bleDevice, false, bleGattCallback, connectRetryCount);
                }
                break;

                case BleMsg.MSG_CONNECT_OVER_TIME: {
                    disconnectGatt();
                    refreshDeviceCache();
                    closeBluetoothGatt();

                    lastState = LastState.CONNECT_FAILURE;
                    BleManager.getInstance().getMultipleBluetoothController().removeConnectingBle(BleBluetooth.this);

                    if (bleGattCallback != null) {
                        bleGattCallback.onConnectFail(bleDevice, new TimeoutException());
                    }
                }
                break;

                case BleMsg.MSG_DISCOVER_SERVICES: {
                    if (bluetoothGatt != null) {
                        boolean discoverServiceResult = bluetoothGatt.discoverServices();
                        if (!discoverServiceResult) {
                            InnerEvent message = InnerEvent.get(BleMsg.MSG_DISCOVER_FAIL);
                            mainHandler.sendEvent(message);
                        }
                    } else {
                        InnerEvent message = InnerEvent.get(BleMsg.MSG_DISCOVER_FAIL);
                        mainHandler.sendEvent(message);
                    }
                }
                break;

                case BleMsg.MSG_DISCOVER_FAIL: {
                    disconnectGatt();
                    refreshDeviceCache();
                    closeBluetoothGatt();

                    lastState = LastState.CONNECT_FAILURE;
                    BleManager.getInstance().getMultipleBluetoothController().removeConnectingBle(BleBluetooth.this);

                    if (bleGattCallback != null) {
                        bleGattCallback.onConnectFail(
                                bleDevice, new OtherException("GATT discover services exception occurred!"));
                    }
                }
                break;

                case BleMsg.MSG_DISCOVER_SUCCESS: {
                    lastState = LastState.CONNECT_CONNECTED;
                    isActiveDisconnect = false;
                    BleManager.getInstance().getMultipleBluetoothController().removeConnectingBle(BleBluetooth.this);
                    BleManager.getInstance().getMultipleBluetoothController().addBleBluetooth(BleBluetooth.this);

                    BleConnectStateParameter para = (BleConnectStateParameter) msg.object;
                    int status = para.getStatus();
                    if (bleGattCallback != null) {
                        bleGattCallback.onConnectSuccess(bleDevice, bluetoothGatt, status);
                    }
                }
                break;

                default:
                    super.processEvent(msg);
                    break;
            }
        }
    }

    private BlePeripheralCallback coreGattCallback =
            new BlePeripheralCallback() {
                @Override
                public void connectionStateChangeEvent(int connectionState) {
                    super.connectionStateChangeEvent(connectionState);
                    mainHandler.removeEvent(BleMsg.MSG_CONNECT_OVER_TIME);

                    if (connectionState == ProfileBase.STATE_CONNECTED) {
                        InnerEvent innerEvent = InnerEvent.get(BleMsg.MSG_DISCOVER_SERVICES);
                        mainHandler.sendEvent(innerEvent, 500);

                    } else if (connectionState == ProfileBase.STATE_DISCONNECTED) {
                        InnerEvent innerEvent = InnerEvent.get(BleMsg.MSG_DISCONNECTED);
                        BleConnectStateParameter para = new BleConnectStateParameter(connectionState);
                        para.setActive(isActiveDisconnect);
                        innerEvent.object = para;
                        mainHandler.sendEvent(innerEvent);
                    } else if (connectionState == ProfileBase.STATE_CONNECTING) {
                        InnerEvent innerEvent = InnerEvent.get(BleMsg.MSG_CONNECT_FAIL);
                        innerEvent.object = new BleConnectStateParameter(connectionState);
                        mainHandler.sendEvent(innerEvent);
                    }
                }

                @Override
                public void servicesDiscoveredEvent(int status) {
                    super.servicesDiscoveredEvent(status);
                    if (status == BlePeripheralDevice.OPERATION_SUCC) {
                        InnerEvent innerEvent = InnerEvent.get(BleMsg.MSG_DISCOVER_SUCCESS);
                        innerEvent.object = new BleConnectStateParameter(status);
                        mainHandler.sendEvent(innerEvent);

                    } else {
                        InnerEvent innerEvent = InnerEvent.get(BleMsg.MSG_DISCOVER_FAIL);
                        mainHandler.sendEvent(innerEvent);
                    }
                }

                @Override
                public void characteristicChangedEvent(GattCharacteristic characteristic) {
                    super.characteristicChangedEvent(characteristic);
                    Iterator iterator = bleNotifyCallbackHashMap.entrySet().iterator();
                    while (iterator.hasNext()) {
                        Map.Entry entry = (Map.Entry) iterator.next();
                        Object callback = entry.getValue();
                        if (callback instanceof BleNotifyCallback) {
                            BleNotifyCallback bleNotifyCallback = (BleNotifyCallback) callback;
                            if (characteristic.getUuid().toString().equalsIgnoreCase(bleNotifyCallback.getKey())) {
                                EventHandler handler = bleNotifyCallback.getHandler();
                                if (handler != null) {
                                    InnerEvent message = InnerEvent.get(BleMsg.MSG_CHA_NOTIFY_DATA_CHANGE);
                                    message.object = bleNotifyCallback;
                                    PacMap bundle = new PacMap();
                                    bundle.putByteValueArray(BleMsg.KEY_NOTIFY_BUNDLE_VALUE, characteristic.getValue());
                                    message.setPacMap(bundle);
                                    handler.sendEvent(message);
                                }
                            }
                        }
                    }

                    iterator = bleIndicateCallbackHashMap.entrySet().iterator();
                    while (iterator.hasNext()) {
                        Map.Entry entry = (Map.Entry) iterator.next();
                        Object callback = entry.getValue();
                        if (callback instanceof BleIndicateCallback) {
                            BleIndicateCallback bleIndicateCallback = (BleIndicateCallback) callback;
                            if (characteristic.getUuid().toString().equalsIgnoreCase(bleIndicateCallback.getKey())) {
                                EventHandler handler = bleIndicateCallback.getHandler();
                                if (handler != null) {
                                    InnerEvent message = InnerEvent.get(BleMsg.MSG_CHA_INDICATE_DATA_CHANGE);
                                    message.object = bleIndicateCallback;
                                    PacMap bundle = new PacMap();
                                    bundle.putByteValueArray(
                                            BleMsg.KEY_INDICATE_BUNDLE_VALUE, characteristic.getValue());
                                    message.setPacMap(bundle);
                                    handler.sendEvent(message);
                                }
                            }
                        }
                    }
                }

                @Override
                public void characteristicReadEvent(GattCharacteristic characteristic, int status) {
                    super.characteristicReadEvent(characteristic, status);
                    Iterator iterator = bleReadCallbackHashMap.entrySet().iterator();
                    while (iterator.hasNext()) {
                        Map.Entry entry = (Map.Entry) iterator.next();
                        Object callback = entry.getValue();
                        if (callback instanceof BleReadCallback) {
                            BleReadCallback bleReadCallback = (BleReadCallback) callback;
                            if (characteristic.getUuid().toString().equalsIgnoreCase(bleReadCallback.getKey())) {
                                EventHandler handler = bleReadCallback.getHandler();
                                if (handler != null) {
                                    InnerEvent message = InnerEvent.get(BleMsg.MSG_CHA_READ_RESULT);
                                    message.object = bleReadCallback;
                                    PacMap bundle = new PacMap();
                                    bundle.putIntValue(BleMsg.KEY_READ_BUNDLE_STATUS, status);
                                    bundle.putByteValueArray(BleMsg.KEY_READ_BUNDLE_VALUE, characteristic.getValue());
                                    message.setPacMap(bundle);
                                    handler.sendEvent(message);
                                }
                            }
                        }
                    }
                }

                @Override
                public void characteristicWriteEvent(GattCharacteristic characteristic, int status) {
                    super.characteristicWriteEvent(characteristic, status);
                    Iterator iterator = bleWriteCallbackHashMap.entrySet().iterator();
                    while (iterator.hasNext()) {
                        Map.Entry entry = (Map.Entry) iterator.next();
                        Object callback = entry.getValue();
                        if (callback instanceof BleWriteCallback) {
                            BleWriteCallback bleWriteCallback = (BleWriteCallback) callback;
                            if (characteristic.getUuid().toString().equalsIgnoreCase(bleWriteCallback.getKey())) {
                                EventHandler handler = bleWriteCallback.getHandler();
                                if (handler != null) {
                                    InnerEvent message = InnerEvent.get(BleMsg.MSG_CHA_WRITE_RESULT);
                                    message.object = bleWriteCallback;
                                    PacMap bundle = new PacMap();
                                    bundle.putIntValue(BleMsg.KEY_WRITE_BUNDLE_STATUS, status);
                                    bundle.putByteValueArray(BleMsg.KEY_WRITE_BUNDLE_VALUE, characteristic.getValue());
                                    message.setPacMap(bundle);
                                    handler.sendEvent(message);
                                }
                            }
                        }
                    }
                }

                @Override
                public void readRemoteRssiEvent(int rssi, int ret) {
                    super.readRemoteRssiEvent(rssi, ret);
                    if (bleRssiCallback != null) {
                        EventHandler handler = bleRssiCallback.getHandler();
                        if (handler != null) {
                            InnerEvent message = InnerEvent.get(BleMsg.MSG_READ_RSSI_RESULT);
                            message.object = bleRssiCallback;
                            PacMap bundle = new PacMap();
                            bundle.putIntValue(BleMsg.KEY_READ_RSSI_BUNDLE_STATUS, ret);
                            bundle.putIntValue(BleMsg.KEY_READ_RSSI_BUNDLE_VALUE, rssi);
                            message.setPacMap(bundle);
                            handler.sendEvent(message);
                        }
                    }
                }

                @Override
                public void mtuUpdateEvent(int mtu, int ret) {
                    super.mtuUpdateEvent(mtu, ret);
                    if (bleMtuChangedCallback != null) {
                        EventHandler handler = bleMtuChangedCallback.getHandler();
                        if (handler != null) {
                            InnerEvent message = InnerEvent.get(BleMsg.MSG_SET_MTU_RESULT);
                            message.object = bleMtuChangedCallback;
                            PacMap bundle = new PacMap();
                            bundle.putIntValue(BleMsg.KEY_SET_MTU_BUNDLE_STATUS, ret);
                            bundle.putIntValue(BleMsg.KEY_SET_MTU_BUNDLE_VALUE, mtu);
                            message.setPacMap(bundle);
                            handler.sendEvent(message);
                        }
                    }
                }

                @Override
                public void descriptorReadEvent(GattDescriptor descriptor, int ret) {
                    super.descriptorReadEvent(descriptor, ret);
                }

                @Override
                public void descriptorWriteEvent(GattDescriptor descriptor, int status) {
                    super.descriptorWriteEvent(descriptor, status);
                    Iterator iterator = bleNotifyCallbackHashMap.entrySet().iterator();
                    while (iterator.hasNext()) {
                        Map.Entry entry = (Map.Entry) iterator.next();
                        Object callback = entry.getValue();
                        if (callback instanceof BleNotifyCallback) {
                            BleNotifyCallback bleNotifyCallback = (BleNotifyCallback) callback;
                            if (descriptor
                                    .getCharacteristic()
                                    .getUuid()
                                    .toString()
                                    .equalsIgnoreCase(bleNotifyCallback.getKey())) {
                                EventHandler handler = bleNotifyCallback.getHandler();
                                if (handler != null) {
                                    InnerEvent message = InnerEvent.get(BleMsg.MSG_CHA_NOTIFY_RESULT);
                                    message.object = bleNotifyCallback;
                                    PacMap bundle = new PacMap();
                                    bundle.putIntValue(BleMsg.KEY_NOTIFY_BUNDLE_STATUS, status);
                                    message.setPacMap(bundle);
                                    handler.sendEvent(message);
                                }
                            }
                        }
                    }

                    iterator = bleIndicateCallbackHashMap.entrySet().iterator();
                    while (iterator.hasNext()) {
                        Map.Entry entry = (Map.Entry) iterator.next();
                        Object callback = entry.getValue();
                        if (callback instanceof BleIndicateCallback) {
                            BleIndicateCallback bleIndicateCallback = (BleIndicateCallback) callback;
                            if (descriptor
                                    .getCharacteristic()
                                    .getUuid()
                                    .toString()
                                    .equalsIgnoreCase(bleIndicateCallback.getKey())) {
                                EventHandler handler = bleIndicateCallback.getHandler();
                                if (handler != null) {
                                    InnerEvent message = InnerEvent.get(BleMsg.MSG_CHA_INDICATE_RESULT);
                                    message.object = bleIndicateCallback;
                                    PacMap bundle = new PacMap();
                                    bundle.putIntValue(BleMsg.KEY_INDICATE_BUNDLE_STATUS, status);
                                    message.setPacMap(bundle);
                                    handler.sendEvent(message);
                                }
                            }
                        }
                    }
                }
            };

    enum LastState {
        CONNECT_IDLE,
        CONNECT_CONNECTING,
        CONNECT_CONNECTED,
        CONNECT_FAILURE,
        CONNECT_DISCONNECT
    }
}
